
import { JXBezierTo, JXMoveTo } from "../../../Core/FrameEx/ActionEx";
import { CCNodeImpl } from "../../../Core/FrameEx/CCNodeImpl";
import MathEx from "../../../Core/Math/MathEx";
import { JXBtlArrIx } from "./JXBattleDefine";
import JXRBCmdMgr from "./JXRBCmdMgr";
import { JXRBRole } from "./JXRBRole";
import { JXRBScript } from "./JXRBScript";
import { COMMON_ANI_NAME, JXBattleBulletRoot, JXBattleSkillSpine, JXEBulleType, JXEDir, JXRB_LAYER_INDEX } from './JXULDefine';


export class JXRBBullet extends CCNodeImpl {
	protected _moveAction: any;
	protected _startDisplay: cc.ActionInstant;
	protected _otherAction: cc.ActionInterval;
	protected _bulletConfig: SBulletRaw;

	public order: number;
	protected delayOffset: number;

	protected gunner: JXRBRole;
	protected script: JXRBScript;
	public hiter: JXRBRole;

	/** 如果时技能，则执行子弹携带的内容 */
	protected _endExec: JXAnsSkillEffect[];

	protected _clip: cc.AnimationClip;
	protected _cmd: JXRBCmdMgr = null;

	constructor(bulletConfig: SBulletRaw, script: JXRBScript, cmd: JXRBCmdMgr) {
		super(new cc.Node(bulletConfig.id + ''));
		this._bulletConfig = bulletConfig;
		this._cmd = cmd;
		this.bindScript(script);
		if (!!bulletConfig.isSpine) {
			this.loadSpine(bulletConfig.aniconfig);
		}
		else {
			this.loadFrames(bulletConfig.aniconfig as any);
		}
	}

	public bindRoute(action: cc.ActionInterval) {
		this._moveAction = action;
		return this;
	}

	public bindScript(sc: JXRBScript) {
		this.script = sc;
		this.gunner = this.script.execer;
		this.zIndex = JXRB_LAYER_INDEX.ROLE_SPECIAL + JXRB_LAYER_INDEX.BLACK + JXRB_LAYER_INDEX.SCENE_EFFECT_UPPER;
		this.parent = this.gunner.parent;
		return this;
	}

	public bindHiter(role: JXRBRole) {
		this.hiter = role;
		return this;
	}

	public bindOrder(order: number) {
		this.order = order;
		return this;
	}

	public bindDelayOffset(offset: number) {
		this.delayOffset = offset;
		return this;
	}

	public bindEndExc(effect: JXAnsSkillEffect[]) {
		this._endExec = effect;
		return this;
	}

	public get endExec() {
		return this._endExec;
	}

	public loadSpine(aniConfig: any[]) {
		let sk = this.createBySpineConfig(aniConfig)
		let supConfig1 = this._bulletConfig.supAction1;
		let supSk1 = supConfig1 ? this.createBySpineConfig(supConfig1) : null;
		if (supSk1) {
			supSk1.node.position = cc.v2(supConfig1[JXBtlArrIx.Two, JXBtlArrIx.Three])
			sk.node.addChild(supSk1.node);
		}
		this._startDisplay = cc.callFunc(() => {
			if (supSk1) {
				supSk1.setAnimation(0, supConfig1[JXBtlArrIx.One], false);
			}
			sk.setAnimation(0, aniConfig[JXBtlArrIx.One], true);
		})
		sk.node.parent = this.target;
	}

	public createBySpineConfig(aniConfig: any[]) {
		let node = new cc.Node();
		let sk = node.addComponent(sp.Skeleton);
		sk.premultipliedAlpha = !!aniConfig[JXBtlArrIx.Four];
		let skData = this._cmd.assetManager.assetImpl.getPreLoadAsset<sp.SkeletonData>(JXBattleSkillSpine + aniConfig[JXBtlArrIx.Zero]);
		sk.skeletonData = skData;
		node.scale = aniConfig[JXBtlArrIx.Five];
		node.anchorY = 0;
		node.opacity = aniConfig[JXBtlArrIx.Six] * 255;
		return sk;
	}

	public loadFrames(aniConfig: FrameAniConfigure) {
		let animation = this._cmd.assetManager.createEffect(aniConfig, JXBattleBulletRoot, !this._bulletConfig.duration ? cc.WrapMode.Normal : cc.WrapMode.Loop);
		let opacity = animation.node.opacity;
		animation.node.opacity = 255;
		this.opacity = opacity;
		let scale = animation.node.scale;
		this.scale = scale;
		animation.node.scale = 1;
		animation.node.anchorY = 0.5;
		this._startDisplay = cc.callFunc(() => {
			animation.play(COMMON_ANI_NAME);
		})
		this._clip = animation.getClips()[JXBtlArrIx.Zero];
		animation.node.parent = this.target;
	}

	public generate() {
		let startOffset = cc.v2(this._bulletConfig.param1[0] || 0, this._bulletConfig.param1[1] || 0);
		startOffset.x = this.script.execer.dir * startOffset.x;
		let airOffset = cc.v2(this._bulletConfig.param1[2] || 0, this._bulletConfig.param1[3] || 0);
		let otherConfig = this._bulletConfig.param4;
		let dir: number = 1;
		let time = this._bulletConfig.duration || this._clip.duration
		switch (this._bulletConfig.scType) {
			case JXEBulleType.Line: {
				this.position = cc.v2(this.script.execer.x, this.script.execer.y + this.script.execer.skeleton.node["sHeight"] / 2).addSelf(startOffset);
				let airPos = this.hiter.position;
				airPos.y += this.hiter.skeleton.node["sHeight"] / 2;
				airPos.addSelf(airOffset);
				dir = this.position.x > airPos.x ? JXEDir.Left : JXEDir.Right;
				this._moveAction = new JXMoveTo(time, airPos);
				break;
			}
			case JXEBulleType.Curve: {
				// let angle = MathEx.getAngleX(this.position, this.hiter.position);
				this.position = cc.v2(this.script.execer.x, this.script.execer.y + this.script.execer.skeleton.node["sHeight"] / 2).addSelf(startOffset);
				let airPos = this.hiter.position;
				airPos.y += this.hiter.skeleton.node["sHeight"] / 2;
				airPos.addSelf(airOffset);
				dir = this.position.x > airPos.x ? JXEDir.Left : JXEDir.Right;
				let bzs = [];
				let localBz1 = MathEx.getAnglePos((this._bulletConfig.param2[0] + Math.floor(Math.random() * (this._bulletConfig.param3[0] || 0))), this._bulletConfig.param2[1] + Math.floor(Math.random() * (this._bulletConfig.param3[1] || 0)));
				localBz1.x *= dir;
				let bz1 = this.position.add(localBz1);
				bzs.push(bz1);
				if (this._bulletConfig.param2[2] != null) {
					let localBz2 = MathEx.getAnglePos((this._bulletConfig.param2[2] + Math.floor(Math.random() * (this._bulletConfig.param3[2] || 0))), this._bulletConfig.param2[3] + Math.floor(Math.random() * (this._bulletConfig.param3[3] || 0)))
					localBz2.x *= dir;
					let bz2 = airPos.add(localBz2);
					bzs.push(bz2);
				}
				bzs.push(airPos);
				this._moveAction = new JXBezierTo(time, bzs);
				break;
			}
			case JXEBulleType.Vertical: {
				let airPos = this.hiter.position.add(airOffset);
				let pos = MathEx.getAnglePos(90 + -this.hiter.dir * this._bulletConfig.param2[0], this._bulletConfig.param2[1]);
				this.position = pos.add(airPos).addSelf(startOffset);
				dir = this.position.x > airPos.x ? JXEDir.Left : JXEDir.Right;
				this._moveAction = new JXMoveTo(time, airPos);
				break;
			}
		}

		if (this._bulletConfig.ease && cc[this._bulletConfig.ease]) {
			this._moveAction = this._moveAction.easing(cc[this._bulletConfig.ease]());
		}

		for (let i = 0, c = this.target.children, l = c.length; i < l; i++) {
			c[i].scaleY *= dir;
		}

		if (otherConfig && otherConfig.length > 0) {
			let actions = [];
			for (let i = 0; i < otherConfig.length; i++) {
				let [time, scale, fade] = otherConfig[i];
				if (!time) continue;
				let aScale = scale ? cc.scaleTo(time, scale) : null;
				let aFade = fade ? cc.fadeTo(time, fade * 255) : null;
				if (aScale && aFade) {
					actions.push(cc.spawn(aScale, aFade));
				}
				else {
					actions.push(aScale ? aScale : aFade);
				}
			}
			this._otherAction = null;
			if (actions.length > 0) {
				if (actions.length == 1) {
					this._otherAction = actions.pop();
				} else {
					this._otherAction = cc.sequence(actions);
				}
			}
		}
		this.target.active = false;
		return this;
	}

	public shoot() {
		if (!this._startDisplay) return;
		if (!this._moveAction) return;
		let delayTotal = 0;
		if (this.delayOffset) delayTotal += this.delayOffset;
		if (this._bulletConfig.interval && this.order != 0) delayTotal += this._bulletConfig.interval * this.order;
		let spawActions = [this._startDisplay, this._moveAction];
		if (this._otherAction) spawActions.push(this._otherAction);
		let comb = cc.spawn(spawActions);
		let endCb = cc.callFunc(this.onRouteEnd, this);
		let seq: cc.ActionInterval;
		if (delayTotal) {
			seq = cc.sequence(cc.delayTime(delayTotal), comb, endCb);
		}
		else {
			seq = cc.sequence(comb, endCb);
		}
		this.target.active = true;
		this.target.runAction(seq);
	}

	public onRouteEnd() {
		this.hiter.btlActionMgr.removeAllActionsFromTarget(this.target, true);
		this._moveAction = null;
		this._startDisplay = null;
		this._otherAction = null;
		this.target.destroy();
		this.script.onBulletCollision(this);
	}

	public destroy() {
		this.hiter.btlActionMgr.removeAllActionsFromTarget(this.target, true);
		this._moveAction = null;
		this._startDisplay = null;
		this._otherAction = null;
		this.target.destroy();
		this.hiter = null;
		this._clip = null;
		this.script = null;
		this._cmd = null;
	}

}